#ifndef __NPC__NATIVE_EXCEPTION_H__
#define __NPC__NATIVE_EXCEPTION_H__

#include <string>
#include <exception>

#define npc_throw(Exception, message) throw new NativeException(string(__FILE__)+string("@")+string(__PRETTY_FUNCTION__)+": "+(message))
#define npc_throw(Exception, message, cause) throw new NativeException(string(__FILE__)+string("@")+string(__PRETTY_FUNCTION__)+": "+(message), cause)

using namespace std;

namespace estadistec{

	class NativeException/*: public virtual exception*/{

	protected:

		/**
		* message con un descripcion de la NativeException que acaba de ocurrir.
		*/
		string message;

		/**
		* NativeException Causente del problema.
		* */
		NativeException* cause;


	public:

		NativeException()
		{
			generateMessage();
		}

		/**
		* @param cause
		* */
		NativeException(NativeException* cause)
		{
			//printf("inciando NativeException con cause\n");
			this->cause = cause;
			inicializarmessage();
		}


		/**
		* @param message
		* */
		NativeException(string message)
		{
			//printf("inciando NativeException\n");
			this->cause = NULL;
			inicializarmessage();
			message += " - " + messagePersonalizado;
			//printf("NativeException iniciada ");
		}


		/**
		* @param message
		* @param cause
		* */
		NativeException(string message,NativeException* cause)
		{
			//printf("inciando NativeException con cause y message\n");
			this->cause = cause;
			inicializarmessage();
			message += " - "+messagePersonalizado;
		}


		virtual ~NativeException() {
		};



	public:
		/**
		* Metodo para obtener el nombre de la clase analoga en java de forma que esta sea la que
		* se levante en java
		* */
		virtual string getJavaClassName(){
			//Se coloca el nombre de la clase en Java, junto con los paquetes
			return string("setvor.npc.NativeException");
		}

		virtual string getJavaClassSignature(){
			//Se coloca el nombre de la clase en Java, junto con los paquetes
			return string("Lsetvor/npc/NativeException;");
		}


		/**
		* Este message es la descripcion de la NativeException que se levanta desde cpp
		* el cual est'a construido de la forma:
		* <exception> 
		* 		<message>
		* 		Texto de la NativeException
		* 		</message>
		* 		<stack>
		* 			<exception>
		* 				<class>
		* 					Nombre de la clase
		* 				</class>
		* 				<message>
		* 				</message>
		* 			<exception>
		* 			...
		* 		</stack>
		* </exception>
		* */
		string getMessageToJava(){
			//printf("elaborando NativeException\n");
			string message = string("<exception>")+
				"<message>"+
				getmessage()+
				"</message>"+
				"<stack>"+
				getMessageToJavaAux()+
				"</stack>"+
				"</exception>";
			return message;
		}


	protected:

		string getMessageToJavaAux(){
			return getCause()? 
				string("<exception>")+
				"<class>"+
				getCause()->getJavaClassName()+
				"</class>"+
				"<message>"+
				getCause()->getmessage()+
				"</message>"+
				"</exception>"+
				getCause()->getMessageToJavaAux()
				:string("");
		}

	protected:

		/**
		* Metodo para inicializar los messages como respuesta al error.
		* */
		virtual void generateMessage()
		{
			message = "generic message";
		}


	public:

		/**
		* Metodo el cual es el encargado de retornar el message que se mostrara
		* al usuario como explicacion por lo sucedido.
		* */
		string getMessage()
		{
			return message;
		}

		/**
		* Metodo encargado de retornar la NativeException
		* */
		NativeException* getCause()
		{
			return  cause;
		}


		/**
		* Metodo para imprimir los ultimos eventos en la pila
		* */
		string* getPilaDelRastro();

		/**
		* Metodo para imprimir  el message de error
		* */

	};

};

#endif